#

| Chapter 48 Office Automation |

## 48.4 Automatic Reminders and More: calendar

If you type the command calendar, you'll see lines with "to-do" items for today and tomorrow from a file named calendar in your current directory. If you put that file in your home directory, your system administrator can run the command calendar-to mail (1.33) everyones' "to-do" items to them. You can also automate your personal calendar setup by running calendar yourself - the calendar can be mailed to you, sent to the printer, and so on, first thing each morning. See below for an example calendar file and more information.

calendar builds a complicated egrep (27.5) expression to search your calendar file. You can see that expression yourself if you want to.

### 48.4.1 How calendar Works

Let's start by showing a few lines of a sample calendar file. (Yours can be much longer.) Then I'll run calendar to show what lines it picks:

>     % cat calendar
>     -- WORK --
>     12/28   Project report due tomorrow!
>     -- PERSONAL --
>     * 8       rub Lisa's feet
>     Take Lisa out to dinner on December 8
>     dec 9     buy Lisa lunch
>     On 12/10, Lisa will be hungry for ice cream
>     -- BIRTHDAYS --
>     1/1 Mom's birthday - make dinner reservations by 12/20!
>     % date
>     Tue Dec  8 08:43:40 PST 1992
>     % calendar
>     * 8       rub Lisa's feet
>     Take Lisa out to dinner on December 8
>     dec 9     buy Lisa lunch

Today is December 8. The calendar utility found lines in my calendar file for today and tomorrow. calendar understands lots of date formats. The date can be anywhere on a line. If you leave a line in your file for more than one year (like Mom's birthday) calendar will show it every year. If a line has more than one date, you'll see the line on both of those dates (I'll be reminded before Mom's birthday and also in time to make a dinner reservation). An asterisk (`*`) in place of a month means "all months."

Many versions of calendar utility run your calendar file through the C language preprocessor, cpp. Among other things, this lets you include several calendar files in your own calendar file. Lines that start with a hash mark (`#`) in column 1 are read by the preprocessor. For instance, this line in your calendar file would include all the contents of the file /usr/local/lib/office.calendar just as if you'd typed them into your own file:

>     #include "/usr/local/lib/office.calendar"

Someone (the office secretary) can maintain the office.calendar file. People in the office who want reminders from it can put the `#include` line in their own calendar files.

By the way, if you start a line with `#` and it's not for the preprocessor, you'll get a mysterious error like `calendar:` `1:` `undefined` `control`. That means line 1 of the file had something the preprocessor couldn't understand.

### 48.4.2 The egrep Expression calendar Uses

How can calendar find dates in all the formats it accepts - and only for today and tomorrow? It runs a system program, usually named /usr/lib/calendar, that generates an expression for egrep -f (27.7). The expression searches for the dates of today and tomorrow; if today is a Friday, the expression includes dates on Saturday, Sunday, and Monday. Here's the expression I got by running /usr/lib/calendar on Tuesday, December 8. TAB characters are shown as `T`; spaces are shown as .

>     % /usr/lib/calendar
>     (^|[T(,;])((([Dd]ec[^T]*|\*)[T]*|(012|12|\*)/)0*8)([^0123456789]|$)
>     (^|[T(,;])((([Dd]ec[^T]*|\*)[T]*|(012|12|\*)/)0*9)([^0123456789]|$)

I'll turn the first line of that into English. I'm not writing this just for egrep fanatics `:-)`; this is also useful for understanding what kinds of dates calendar will recognize. I'm going to skip some not-so-subtle things like the nesting of the parentheses and just give an overview. If you haven't seen extended regular expressions before, see article 26.4. The expression finds lines in your calendar file that meet these conditions, in order from left to right across the line:

`(^|[T(,;])`

  This matches whatever comes before the date. Match at the beginning of a line (`^`) or (`|`) match a space, TAB, opening parenthesis, comma, or semicolon (`[T(,;]`). This keeps egrep from matching other words that start with or contain the month abbreviation `[Dd]ec`.

`((([Dd]ec[^T]*|\*)[T]*|(012|12|\*)/)0*8)`

  This matches the date. Match Dec or dec with zero or more of any character besides space or TAB after that (`[Dd]ec[^T]*`)-or (`|`) have a literal asterisk (`\*`), which means "match this on any month of the year." Or (`|`) match a numeric month like 012 or 12 or a literal asterisk (`(012|12|\*)`)-followed by a slash (`/`). Finally, you need today's date: it starts with any number of zeros and ends with 8 (`)0*8)`).

`([^0123456789]|$)`

  The end of the expression matches lines anything except a digit - or matches the end of the line. This keeps egrep from matching non-dates like 8.75.

Whew. That expression is repeated for every other day that needs to be matched. On Fridays, the output of /usr/lib/calendar has four lines - one each for Friday, Saturday, Sunday, and Monday.

### 48.4.3 Automating Your Own Calendar

If you want a calendar every weekday, put a line like the following into your personal crontab file (40.12). We've split this onto two lines for printing, but you should type it all on one line:

    $USER
    && <
    6 6 * * 1-5 tf=/tmp/cal.$USER; umask 077; /bin/calendar > $tf;
        test -s $tf && mail -s 'Calendar for today' $USER < $tf; rm -f $tf

That runs calendar from my home directory at 6:06 a.m. (40.5) every weekday morning. It sets a Bourne shell variable (6.8) named tf with the name of a temporary file in the /tmp directory (21.3), and sets a umask (22.4) to make the file private. Then it runs calendar and saves the output in the temporary file. If there's a calendar for today, the mail command sends the file to me. (The -s option on our mail command adds the `Subject:` line Calendar for today to the message. It isn't required.) Finally, the temporary file is removed.

If you don't have personal crontabs, you can use a self-restarting at job (40.8) and the nextweekday script (40.10) instead.

- JP

48.3 A Scratchpad on Your Screen |  | 48.5 leave: A Maddening Aid to Quitting on Time